package org.listbeast.core.datasource.impl;

import java.io.File;
import java.io.IOException;
import java.util.Collection;

import org.apache.commons.io.FileUtils;
import org.apache.log4j.Logger;
import org.jaudiotagger.audio.AudioFile;
import org.jaudiotagger.audio.AudioFileIO;
import org.jaudiotagger.audio.exceptions.CannotReadException;
import org.jaudiotagger.audio.exceptions.InvalidAudioFrameException;
import org.jaudiotagger.audio.exceptions.ReadOnlyFileException;
import org.jaudiotagger.tag.FieldKey;
import org.jaudiotagger.tag.Tag;
import org.jaudiotagger.tag.TagException;
import org.listbeast.core.dataobjects.DiskSong;
import org.listbeast.core.dataobjects.SongCollection;
import org.listbeast.core.dataobjects.SongCollectionImpl;
import org.listbeast.core.datasource.SongReader;

public class FileSystemSongReader implements SongReader {

	private static final Logger LOG = Logger.getLogger(FileSystemSongReader.class);
	private final String rootPath;

	public FileSystemSongReader(String rootPath) {
		this.rootPath = rootPath;
	}

	public SongCollection<DiskSong> getSongs() {
		LOG.info("FileSystemSongReader: getSongs() - Directory root path= " + rootPath);

		Collection<File> files = listAllFiles(rootPath);

		SongCollection<DiskSong> diskSongs = new SongCollectionImpl<DiskSong>();
		addLibraryItems(files, diskSongs);

		writeLogFile(diskSongs);

		return diskSongs;
	}

	private Collection<File> listAllFiles(String libraryRootPath) {
		File libraryRootDir = new File(libraryRootPath);
		String[] extensions = { "mp3" };
		Collection<File> files = FileUtils.listFiles(libraryRootDir, extensions, true /* recursive */);
		return files;
	}

	/**
	 * Method utilizes jaudiotagger library to get the audio tags from the song
	 * files
	 * 
	 * @param files
	 * @param diskSongs
	 * @return
	 */
	private void addLibraryItems(Collection<File> files,
			SongCollection<DiskSong> diskSongs) {

		for (File file : files) {
			AudioFile f;
			try {
				f = AudioFileIO.read(file);
				Tag tag = f.getTag();

				if (tag != null) {
					String artist = tag.getFirst(FieldKey.ARTIST) != null ? tag.getFirst(FieldKey.ARTIST).toLowerCase()
							: "";
					String title = tag.getFirst(FieldKey.TITLE);
					String filePath = file.getAbsolutePath();

					if (artist.equals("")) {
						LOG.warn("File " + file.getName()
								+ " has no artist defined in tag!");
						continue; // song without artist tag is not stored in
									// cache
					}
					if (title.equals("")) {
						LOG.warn("File " + file.getName()
								+ " has no song title defined in tag!");
						continue; // song without title tag is not stored in
									// cache
					}

					diskSongs.addSong(new DiskSong(artist, title, filePath));

				} else {
					LOG.warn("File " + file.getName() + " contains no tag!");
				}
			} catch (CannotReadException e) {
				LOG.error(e);
			} catch (IOException e) {
				LOG.error(e);
			} catch (TagException e) {
				LOG.error(e);
			} catch (ReadOnlyFileException e) {
				LOG.error(e);
			} catch (InvalidAudioFrameException e) {
				LOG.error(e);
			}
		}
	}

	private void writeLogFile(SongCollection<DiskSong> musicLibrary) {

		Collection<String> artistNames = musicLibrary.getArtistNames();
		LOG.info("Identified " + artistNames.size() + " artists.");

		for (String artist : artistNames) {
			LOG.info("-----------------------");
			LOG.info("                       ");
			LOG.info("Artist name:" + artist);
			LOG.info("                       ");
			Collection<DiskSong> artistSongs = musicLibrary.getArtistSongs(artist);
			for (DiskSong song : artistSongs) {
				LOG.info(song.getTitle());
			}
		}
	}

}
